package com.moxi.mogublog.utils;

import com.moxi.mogublog.constants.CommonConstant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * IP相关工具类（需要连接公网）
 *
 * @author JackLi
 * @date 2020年05月290日 10:36:35
 */
public class IpUtils {

    public static final Logger log = LoggerFactory.getLogger(IpUtils.class);

    private static String unknownStr = "unknown";
    private static String localhostIp = "127.0.0.1";
    private static String localhostIpv6 = "0:0:0:0:0:0:0:1";

    /**
     * 腾讯位置服务的 key  (JackLi QQ号登录 770304260)
     */
    private static String TENCENT_LBS_KEY = "QKLBZ-PVT33-5773Q-3D44X-RRC5V-XXFH3";

    /**
     * 获取当前网络ip
     *
     * @param request
     * @return
     */
    public static String getIpAddr(HttpServletRequest request) {
        String ipAddress = request.getHeader("x-forwarded-for");
        if (ipAddress == null || ipAddress.length() == CommonConstant.NUM_ZERO || unknownStr.equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.length() == CommonConstant.NUM_ZERO || unknownStr.equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.length() == CommonConstant.NUM_ZERO || unknownStr.equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getRemoteAddr();
            if (localhostIp.equals(ipAddress) || localhostIpv6.equals(ipAddress)) {
                // 根据网卡取本机配置的IP
                InetAddress iNet = null;
                try {
                    iNet = InetAddress.getLocalHost();
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                }
                ipAddress = iNet.getHostAddress();
            }
        }
        //对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割  //"***.***.***.***".length() = 15
        if (ipAddress != null && ipAddress.length() > CommonConstant.NUM_FIFTEEN) {
            if (ipAddress.indexOf(CommonConstant.SYMBOL_POINT) > CommonConstant.NUM_ZERO) {
                ipAddress = ipAddress.substring(CommonConstant.NUM_ZERO, ipAddress.indexOf(CommonConstant.SYMBOL_COMMA));
            }
        }
        return ipAddress;
    }

    /**
     * 获取真实IP
     *
     * @param request
     * @return
     */
    public static String getRealIp(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        return checkIp(ip) ? ip :
                (checkIp(ip = request.getHeader("Proxy-Client-IP")) ? ip :
                        (checkIp(ip = request.getHeader("WL-Proxy-Client-IP")) ? ip : request.getRemoteAddr()));
    }

    /**
     * 校验IP
     *
     * @param ip
     * @return
     */
    private static boolean checkIp(String ip) {
        return !StringUtils.isEmpty(ip) && !unknownStr.equalsIgnoreCase(ip);
    }


    /**
     * 获取操作系统,浏览器及浏览器版本信息
     *
     * @param request
     * @return
     */
    public static Map<String, String> getOsAndBrowserInfo(HttpServletRequest request) {
        String browserDetails = request.getHeader("User-Agent");
        String userAgent = browserDetails;
        String user = userAgent.toLowerCase();

        String os = "";
        String browser = "";

        //=================OS Info=======================
        if (userAgent.toLowerCase().indexOf(CommonConstant.OS_WINDOWS) >= 0) {
            os = "Windows";
        } else if (userAgent.toLowerCase().indexOf(CommonConstant.OS_MAC) >= 0) {
            os = "Mac";
        } else if (userAgent.toLowerCase().indexOf(CommonConstant.OS_UNIX) >= 0) {
            os = "Unix";
        } else if (userAgent.toLowerCase().indexOf(CommonConstant.OS_ANDROID) >= 0) {
            os = "Android";
        } else if (userAgent.toLowerCase().indexOf(CommonConstant.OS_IPHONE) >= 0) {
            os = "IPhone";
        } else {
            os = "UnKnown, More-Info: " + userAgent;
        }
        //===============Browser===========================
        if (user.contains(CommonConstant.BROWSER_EDGE)) {
            browser = (userAgent.substring(userAgent.indexOf("Edge")).split(" ")[0]).replace("/", "-");
        } else if (user.contains(CommonConstant.BROWSER_MSIE)) {
            String substring = userAgent.substring(userAgent.indexOf("MSIE")).split(";")[0];
            browser = substring.split(" ")[0].replace("MSIE", "IE") + "-" + substring.split(" ")[1];
        } else if (user.contains(CommonConstant.BROWSER_SAFARI) && user.contains("version")) {
            browser = (userAgent.substring(userAgent.indexOf("Safari")).split(" ")[0]).split("/")[0]
                    + "-" + (userAgent.substring(userAgent.indexOf("Version")).split(" ")[0]).split("/")[1];
        } else if (user.contains("opr") || user.contains("opera")) {
            if (user.contains("opera")) {
                browser = (userAgent.substring(userAgent.indexOf("Opera")).split(" ")[0]).split("/")[0]
                        + "-" + (userAgent.substring(userAgent.indexOf("Version")).split(" ")[0]).split("/")[1];
            } else if (user.contains("opr")) {
                browser = ((userAgent.substring(userAgent.indexOf("OPR")).split(" ")[0]).replace("/", "-"))
                        .replace("OPR", "Opera");
            }
        } else if (user.contains(CommonConstant.BROWSER_CHROME)) {
            browser = (userAgent.substring(userAgent.indexOf("Chrome")).split(" ")[0]).replace("/", "-");
        } else if ((user.indexOf("mozilla/7.0") > -1) || (user.indexOf("netscape6") != -1) ||
                (user.indexOf("mozilla/4.7") != -1) || (user.indexOf("mozilla/4.78") != -1) ||
                (user.indexOf("mozilla/4.08") != -1) || (user.indexOf("mozilla/3") != -1)) {
            browser = "Netscape-?";

        } else if (user.contains(CommonConstant.BROWSER_FIREFOX)) {
            browser = (userAgent.substring(userAgent.indexOf("Firefox")).split(" ")[0]).replace("/", "-");
        } else if (user.contains("rv")) {
            String IEVersion = (userAgent.substring(userAgent.indexOf("rv")).split(" ")[0]).replace("rv:", "-");
            browser = "IE" + IEVersion.substring(0, IEVersion.length() - 1);
        } else {
            browser = "UnKnown, More-Info: " + userAgent;
        }
        Map<String, String> result = new HashMap<>(CommonConstant.NUM_TWO);
        result.put("OS", os);
        result.put("BROWSER", browser);
        return result;
    }

    /**
     * 判断是否是内网IP
     *
     * @param ip
     * @return
     */
    public static boolean isInner(String ip) {
        String reg = "(10|172|192)\\.([0-1][0-9]{0,2}|[2][0-5]{0,2}|[3-9][0-9]{0,1})\\.([0-1][0-9]{0,2}|[2][0-5]{0,2}|[3-9][0-9]{0,1})\\.([0-1][0-9]{0,2}|[2][0-5]{0,2}|[3-9][0-9]{0,1})";
        Pattern p = Pattern.compile(reg);
        Matcher matcher = p.matcher(ip);
        return matcher.find();
    }

    /**
     * 获取IP地址来源（淘宝）
     *
     * @param content        请求的参数 格式为：name=xxx&pwd=xxx
     * @param encodingString 服务器端请求编码。如GBK,UTF-8等
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String getAddressesTaobao(String content, String encodingString) {
        String ip = content.substring(3);
        // 判断是否是内网op
        if (isInner(ip)) {
            return "XX|XX|内网IP|内网IP";
        }
        // TODO 淘宝接口目前已经宕机，因此暂时注释下面代码 (待修改) -接口增加了 secertKey
//        try {
//            // 这里调用pconline的接口
//            String urlStr = "http://ip.taobao.com/service/getIpInfo.php";
//            // 从http://whois.pconline.com.cn取得IP所在的省市区信息
//            String returnStr = getResult(urlStr, content, encodingString);
//            if (returnStr != null) {
//                // 处理返回的省市区信息
//                log.info("调用IP解析接口返回的内容:" + returnStr);
//                String[] temp = returnStr.split(",");
//                //无效IP，局域网测试
//                if (temp.length < 3) {
//                    return "0";
//                }
//                // 国家
//                String country = "";
//                // 区域
//                String area = "";
//                // 省
//                String region = "";
//                // 市
//                String city = "";
//                // 县
//                String county = "";
//                // 运营商
//                String isp = "";
//                Map<String, Object> map = JsonUtils.jsonToMap(returnStr);
//                if (map.get("code") != null) {
//                    Map<String, String> data = (Map<String, String>) map.get("data");
//                    country = data.get("country");
//                    area = data.get("area");
//                    region = data.get("region");
//                    city = data.get("city");
//                    county = data.get("area");
//                    isp = data.get("isp");
//                }
//                log.info("获取IP地址对应的地址" + country + "=" + area + "=" + region + "=" + city + "=" + county + "=" + isp);
//                StringBuffer result = new StringBuffer();
//                result.append(country);
//                result.append("|");
//                result.append(region);
//                result.append("|");
//                result.append(city);
//                result.append("|");
//                result.append(isp);
//                return result.toString();
//            }
//        } catch (Exception e) {
//            log.error(e.getMessage());
//            return null;
//        }
        return null;
    }

    /**
     * 获取IP地址来源（腾讯）
     *
     * @param content        请求的参数 格式为：name=xxx&pwd=xxx
     * @param encodingString 服务器端请求编码。如GBK,UTF-8等
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String getAddressesTencent(String content, String encodingString) {
        String ip = content.substring(3);
        // 判断是否是内网op
        if (isInner(ip)) {
            return "XX|XX|内网IP|内网IP";
        }
        try {
            // 这里调用 腾讯位置服务 的接口
            // https://apis.map.qq.com/ws/location/v1/ip?ip=222.209.233.186&key=QKLBZ-PVT33-5773Q-3D44X-RRC5V-XXFH3&output=json
            String urlStr = "https://apis.map.qq.com/ws/location/v1/ip";
            content = "output=json&key=" + TENCENT_LBS_KEY + "&" + content;
            String returnStr = HttpRequestUtil.sendGet(urlStr, content);

            // {
            // "status": 0,
            // "message": "query ok",
            // "result": {
            // "ip": "115.239.210.27",
            // "location": {            "lat": 30.27415,            "lng": 120.15515        },
            // "ad_info": {"nation": "中国","province": "浙江省","city": "杭州市","district": "","adcode": 330100}
            // }}
            if (returnStr != null) {
                // 处理返回的省市区信息
                log.info("调用IP解析接口返回的内容:" + returnStr);
                // 国家 / 省 / 市 / district
                String nation = "", province = "", city = "", district = "";
                Map<String, Object> map = JsonUtils.jsonToMap(returnStr);
                Object statusObj = map.get("status");
                if (statusObj != null && statusObj instanceof Double) {
                    Double status = (Double) statusObj;
                    if (Double.valueOf("0.0").equals(status)) {
                        Map<String, Object> resultMap = (Map<String, Object>) map.get("result");
                        Map<String, String> adInfoMap = (Map<String, String>) resultMap.get("ad_info");
                        nation = adInfoMap.get("nation");
                        province = adInfoMap.get("province");
                        city = adInfoMap.get("city");
                        district = adInfoMap.get("district");
                    } else {
                        return map.get("message").toString();
                    }
                }
                log.info("获取IP地址对应的地址" + nation + "=" + province + "=" + city + "=" + district);
                StringBuffer result = new StringBuffer();
                result.append(nation);
                result.append("|");
                result.append(province);
                result.append("|");
                result.append(city);
                result.append("|");
                result.append(district);
                return result.toString();
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            return "网络连接异常";
        }
        return null;
    }

    /**
     * @param urlStr   请求的地址
     * @param content  请求的参数 格式为：name=xxx&pwd=xxx
     * @param encoding 服务器端请求编码。如GBK,UTF-8等
     * @return
     */
    private static String getResult(String urlStr, String content, String method, String encoding) {
        URL url = null;
        HttpURLConnection connection = null;
        try {
            url = new URL(urlStr);
            // 新建连接实例
            connection = (HttpURLConnection) url.openConnection();
            // 设置连接超时时间，单位毫秒
            connection.setConnectTimeout(10000);
            // 设置读取数据超时时间，单位毫秒
            connection.setReadTimeout(10000);
            // 是否打开输出流 true|false
            connection.setDoOutput(true);
            // 是否打开输入流true|false
            connection.setDoInput(true);
            // 提交方法POST|GET
//            connection.setRequestMethod(method);
            // 是否缓存true|false
            connection.setUseCaches(false);
            // 打开连接端口
            connection.connect();
            // 打开输出流往对端服务器写数据
            DataOutputStream out = new DataOutputStream(connection.getOutputStream());
            // 写数据,也就是提交你的表单 name=xxx&pwd=xxx
            out.writeBytes(content);
            // 刷新
            out.flush();
            // 关闭输出流
            out.close();
            // 往对端写完数据对端服务器返回数据
            BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), encoding));
            // ,以BufferedReader流来读取
            StringBuffer buffer = new StringBuffer();
            String line = "";
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }
            reader.close();
            return buffer.toString();
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        } finally {
            if (connection != null) {
                // 关闭连接
                connection.disconnect();
            }
        }
    }

    /**
     * unicode 转换成 中文
     *
     * @param theString
     * @return
     * @author fanhui 2007-3-15
     */
    public static String decodeUnicode(String theString) {
        char aChar;
        int len = theString.length();
        StringBuffer outBuffer = new StringBuffer(len);
        for (int x = 0; x < len; ) {
            aChar = theString.charAt(x++);
            if (aChar == '\\') {
                aChar = theString.charAt(x++);
                if (aChar == 'u') {
                    int value = 0;
                    for (int i = 0; i < 4; i++) {
                        aChar = theString.charAt(x++);
                        switch (aChar) {
                            case '0':
                            case '1':
                            case '2':
                            case '3':
                            case '4':
                            case '5':
                            case '6':
                            case '7':
                            case '8':
                            case '9':
                                value = (value << 4) + aChar - '0';
                                break;
                            case 'a':
                            case 'b':
                            case 'c':
                            case 'd':
                            case 'e':
                            case 'f':
                                value = (value << 4) + 10 + aChar - 'a';
                                break;
                            case 'A':
                            case 'B':
                            case 'C':
                            case 'D':
                            case 'E':
                            case 'F':
                                value = (value << 4) + 10 + aChar - 'A';
                                break;
                            default:
                                throw new IllegalArgumentException(
                                        "Malformed      encoding.");
                        }
                    }
                    outBuffer.append((char) value);
                } else {
                    if (aChar == 't') {
                        aChar = '\t';
                    } else if (aChar == 'r') {
                        aChar = '\r';
                    } else if (aChar == 'n') {
                        aChar = '\n';
                    } else if (aChar == 'f') {
                        aChar = '\f';
                    }
                    outBuffer.append(aChar);
                }
            } else {
                outBuffer.append(aChar);
            }
        }
        return outBuffer.toString();
    }

    /**
     * 测试方法
     *
     * @param args
     */
//    public static void main(String[] args) {
//        String ip = "222.209.233.186";
//        String address = getAddressesTencent("ip=" + ip, "utf-8");
//        System.out.println(address);
//    }

}
